import Vue,{PropOptions,PropType,VNode} from 'vue';
import 'tippy.js/animations/perspective.css';
import Icon from '../icon';
import NumberInput from '../number-input';
import Button from '../button';
import Tippy from '../tippy';
import {Props} from 'tippy.js';
import {AppendTo,PlainObject} from '../../../../types';
import {daysInMonth,startOfDate,endOfDate,dateFormat} from '../../../util/common';
/**
 * 选择器形状
 */
export type ShapeType='square'|'round'|'noBorder';
/**
 * 选择类型
 */
export type chooseType='date'|'datetime'|'dateRange';
//type为 'dateRange' 时, value的类型
export interface RangeValue{
	from:Date,
	to:Date,
}
/**
 * 选日期组件
 * @author 唐国雄
 * @date 2021/8/17
 * 属性----------------------
 * v-model				当前值, null | Date | RangeValue
 * :type				选择类型, chooseType
 * :shape				外形, ShapeType
 * :placeholder			占位文本, string
 * :disable				禁用, boolean
 * :append-to			绑定位置, AppendTo
 * :format				显示格式, string
 * :time-format			显示时间格式, string
 * :start-date			默认显示日期, Date
 * :separator			日期范围的分隔符, string
 * :navigation-min		能导航到的最小日期, null | Date
 * :navigation-max		能导航到的最大日期, null | Date
 * :disable-date		禁用日期
 * :empty-default		空值默认选中当前日期
 * 事件----------------------
 * @input				值改变, null | Date | RangeValue
 */
export default Vue.extend({
	name:'DatePicker',
	props:{
		//当前值
		value:{
			required:true,
			validator(v){
				return v==null||v instanceof Date||(v.from instanceof Date&&v.to instanceof Date);
			}
		} as PropOptions<null|Date|RangeValue>,
		//选择类型
		type:{
			type:String,
			default:'date',
			validator(v){
				return [
					'date',
					'datetime',
					'dateRange',
				].indexOf(v)!==-1;
			}
		} as PropOptions<chooseType>,
		//外形
		shape:{
			type:String,
			default:'square',
			validator(v){
				return [
					'square',
					'round',
					'noBorder',
				].indexOf(v)!==-1;
			}
		} as PropOptions<ShapeType>,
		//占位文本
		placeholder:String,
		//禁用
		disable:Boolean,
		//绑定位置, 默认document.body
		appendTo:{
			type:[String,Element,Function],
			validator(v){
				if(typeof v==='string'){
					return v==='parent';
				}
				return true;
			}
		} as PropOptions<AppendTo>,
		//显示格式
		format:{
			type:String,
			default:'yyyy年 M月d日',
		},
		//显示时间格式
		timeFormat:{
			type:String,
			default:'  HH:mm:ss',
		},
		//默认显示日期
		startDate:Date as PropType<Date>,
		//日期范围的分隔符
		separator:{
			type:String,
			default:' 至 ',
		},
		//能导航到的最小日期
		navigationMin:{
			validator(v){
				return v==null||v instanceof Date;
			}
		} as PropOptions<null|Date>,
		//能导航到的最大日期
		navigationMax:{
			validator(v){
				return v==null||v instanceof Date;
			}
		} as PropOptions<null|Date>,
		//禁用日期
		disableDate:Function,
		//空值默认选中当前日期
		emptyDefault:Boolean,
	},
	data(){
		return {
			//是否聚焦选择器
			focus:false,
			//内部面板设置时间
			innerDate:null as (Date|null),
			//当前时间
			nowDate:startOfDate(new Date(),'day'),
			//内部日期范围开始
			fromDate:null as (null|Date),
			//内部日期范围结束
			toDate:null as (null|Date),
			datetime:null as (null|Date),
			hour:0,
			minute:0,
			second:0,
		};
	},
	computed:{
		classes():string{
			return 'lms-DatePicker'+
				` lms--${this.shape}`+
				(this.focus?' lms--focus':'')+
				(this.value instanceof Date
					?(this.value?' lms--value':'')
					:(this.value&&this.value.from?' lms--value':'')
				)+
				(this.disable?' lexmis--disable':'');
		},
		//传给Tippy组件的属性
		tippyOptions():PlainObject{
			return {
				advanced:true,
				head:false,
				disable:this.disable,
				appendTo:this.appendTo,
				width:0,
				'tippy-options':{
					arrow:false,
					placement:'bottom-start',
					duration:[300,300],
					animation:'perspective',
					offset:[0,5],
					theme:'lexmis-widget',
				} as Props
			};
		},
		//控件显示值
		showValue():string{
			if(this.value){
				if(this.value instanceof Date){
					let show=dateFormat(this.value,this.format);
					if(this.type==='datetime'){
						show+=dateFormat(this.value,this.timeFormat);
					}
					return show;
				}else{
					return dateFormat(this.value.from,this.format)+
						this.separator+
						dateFormat(this.value.to,this.format);
				}
			}else{
				return '';
			}
		},
		//显示面板的日期
		showPanelDate():Date{
			if(this.value instanceof Date){
				return startOfDate(this.innerDate||this.value||this.startDate||this.nowDate,'month');
			}else{
				return startOfDate(this.innerDate||(this.value&&this.value.from)||this.startDate||this.nowDate,'month');
			}
		},
		//选择的日期, 匹配的天
		valueInfo():{active:Array<number>,contain:(time:number) => boolean}{
			const active:Array<number>=[];
			let contain=function(time:number){
				return false;
			};
			let value=this.value;
			if(this.type==='datetime'&&this.datetime){
				value=this.datetime;
			}
			if(value==null&&this.emptyDefault&&this.type==='datetime'){
				value=this.nowDate;
			}
			if(value!=null){
				if(value instanceof Date){
					if(
						this.showPanelDate.getFullYear()===value.getFullYear()&&
						this.showPanelDate.getMonth()===value.getMonth()
					){
						active.push(value.getDate());
					}
				}else{
					const {from,to}=value;
					if(
						this.showPanelDate.getFullYear()===from.getFullYear()&&
						this.showPanelDate.getMonth()===from.getMonth()
					){
						active.push(from.getDate());
					}
					if(
						this.showPanelDate.getFullYear()===to.getFullYear()&&
						this.showPanelDate.getMonth()===to.getMonth()
					){
						active.push(to.getDate());
					}
					const showPanelTimeStart=this.showPanelDate.getTime();
					const showPanelTimeEnd=endOfDate(this.showPanelDate,'month').getTime();
					const fromTime=from.getTime();
					const toTime=to.getTime();
					if(fromTime<showPanelTimeEnd&&toTime>showPanelTimeStart){
						contain=(time:number) => {
							return fromTime<time&&toTime>time;
						};
					}
				}
			}
			return {active,contain};
		},
		//显示面板的信息
		dataInfo():{maxDay:number,prefix:number}{
			const showPanelDate=this.showPanelDate;
			const maxDay=daysInMonth(showPanelDate);
			const prefix=(showPanelDate.getDay()+35-showPanelDate.getDate())%7;
			return {
				maxDay,
				prefix,
			};
		}
	},
	watch:{
		value:{
			handler(val){
				if(val){
					if(this.type==='date'){
						const date=startOfDate(val,'day');
						if(val.getTime()!==date.getTime()){
							this.$emit('input',date);
						}
					}else if(this.type==='datetime'){
						const date=startOfDate(val,'second');
						if(val.getTime()!==date.getTime()){
							this.$emit('input',date);
						}
					}else{
						let from=startOfDate(val.from,'day');
						let to=startOfDate(val.to,'day');
						if(from.getTime()>to.getTime()){
							const temp=from;
							from=to;
							to=temp;
						}
						if(val.from.getTime()!==from.getTime()||val.to.getTime()!==to.getTime()){
							this.$emit('input',{
								from,
								to,
							});
						}
					}
				}
			},
			immediate:true
		}
	},
	methods:{
		$_lexmis_show(){
			this.focus=true;
			this.innerDate=null;
			this.fromDate=this.toDate=null;
			this.datetime=null;
			if(this.type==='datetime'){
				if(this.value){
					const value=this.value as Date;
					this.hour=value.getHours();
					this.minute=value.getMinutes();
					this.second=value.getSeconds();
				}else{
					this.hour=this.minute=this.second=0;
				}
			}
			this.nowDate=startOfDate(new Date(),'day');
		},
		$_lexmis_hide(){
			this.focus=false;
		},
	},
	render(h):VNode{
		return h(Tippy,{
			ref:'Tippy',
			staticClass:'lms-DatePicker_Tippy',
			props:this.tippyOptions,
			on:{
				show:this.$_lexmis_show,
				hide:this.$_lexmis_hide,
			},
			scopedSlots:{
				content:() => {
					const list=[
						h('div','一'),
						h('div','二'),
						h('div','三'),
						h('div','四'),
						h('div','五'),
						h('div','六'),
						h('div','日'),
					];
					const {
						maxDay,
						prefix,
					}=this.dataInfo;
					for(let i=0;i<prefix;++i){
						list.push(h('div'));
					}
					let from=this.fromDate&&this.fromDate.getTime();
					let to=this.toDate&&this.toDate.getTime();
					let nextContain=function(time:number){
						return false;
					};
					if(from&&to){
						if(from>to){
							const temp=from;
							from=to;
							to=temp;
						}
						nextContain=(time:number) => {
							// @ts-ignore
							return from<time&&to>time;
						};
					}
					const nowTime=this.nowDate.getTime();
					for(let i=1;i<=maxDay;++i){
						const fullYear=this.showPanelDate.getFullYear();
						const month=this.showPanelDate.getMonth();
						const curDate=new Date(fullYear,month,i);
						const curDateTime=curDate.getTime();
						list.push(h('div',{
							staticClass:'lms-DatePicker_day'+
								(nowTime===curDateTime?' lms--nowDay':'')+
								(this.valueInfo.active.indexOf(i)!==-1?' lms--active':'')+
								(this.valueInfo.contain(curDateTime)?' lms--contain':'')+
								(from===curDateTime?' lms--nextFromActive':'')+
								(to===curDateTime?' lms--nextToActive':'')+
								(nextContain(curDateTime)?' lms--nextContain':''),
							on:{
								click:() => {
									if(this.type==='date'){
										// @ts-ignore
										this.$refs.Tippy.hide();
										this.$emit('input',new Date(curDate));
									}if(this.type==='datetime'){
										this.datetime=new Date(curDate);
									}else if(this.type==='dateRange'){
										if(this.fromDate){
											let to=new Date(curDate);
											let from=this.fromDate;
											if(from.getTime()>to.getTime()){
												const temp=from;
												from=to;
												to=temp;
											}
											// @ts-ignore
											this.$refs.Tippy.hide();
											this.fromDate=this.toDate=null;
											this.$emit('input',{
												from,
												to,
											});
										}else{
											this.fromDate=new Date(curDate);
										}
									}
								},
								mouseenter:() => {
									if(this.fromDate){
										this.toDate=new Date(curDate);
									}
								}
							}
						},i+''));
					}
					return h('div',{
						staticClass:'lms-DatePicker_TippyContent'
					},[
						h('div',{
							staticClass:'lms-DatePicker_head'
						},[
							h(Icon,{
								staticClass:'lms-DatePicker_navigate',
								props:{
									name:'first_page'
								},
								on:{
									click:() => {
										const fullYear=this.showPanelDate.getFullYear();
										const month=this.showPanelDate.getMonth();
										this.innerDate=new Date(fullYear-1,month);
									}
								}
							}),
							h(Icon,{
								staticClass:'lms-DatePicker_navigate',
								props:{
									name:'chevron_left'
								},
								on:{
									click:() => {
										const fullYear=this.showPanelDate.getFullYear();
										const month=this.showPanelDate.getMonth();
										this.innerDate=new Date(fullYear,month-1);
									}
								}
							}),
							h('div',{
								staticClass:'lms-DatePicker_text'
							},[
								h('span',this.showPanelDate.getFullYear()+'年'),
								h('span',this.showPanelDate.getMonth()+1+'月'),
							]),
							h(Icon,{
								staticClass:'lms-DatePicker_navigate',
								props:{
									name:'chevron_right'
								},
								on:{
									click:() => {
										const fullYear=this.showPanelDate.getFullYear();
										const month=this.showPanelDate.getMonth();
										this.innerDate=new Date(fullYear,month+1);
									}
								}
							}),
							h(Icon,{
								staticClass:'lms-DatePicker_navigate',
								props:{
									name:'last_page'
								},
								on:{
									click:() => {
										const fullYear=this.showPanelDate.getFullYear();
										const month=this.showPanelDate.getMonth();
										this.innerDate=new Date(fullYear+1,month);
									}
								}
							})
						]),
						h('div',{
							staticClass:'lms-DatePicker_body',
						},list),
						this.type==='datetime'
							?h('div',{
								staticClass:'lms-DatePicker_foot',
							},[
								h(NumberInput,{
									props:{
										value:this.hour,
										hideButton:true,
										precision:0,
										min:0,
										max:23,
									},
									on:{
										input:(val:number) => {
											this.hour=val;
										},
									}
								}),
								h(NumberInput,{
									props:{
										value:this.minute,
										hideButton:true,
										precision:0,
										min:0,
										max:59,
									},
									on:{
										input:(val:number) => {
											this.minute=val;
										},
									}
								}),
								h(NumberInput,{
									props:{
										value:this.second,
										hideButton:true,
										precision:0,
										min:0,
										max:59,
									},
									on:{
										input:(val:number) => {
											this.second=val;
										},
									}
								}),
								h(Button,{
									props:{
										type:'primary',
									},
									on:{
										click:() => {
											const datetime=this.datetime||
												(this.value&&new Date(this.value as Date))||
												(this.emptyDefault?this.nowDate:null);
											this.datetime=null;
											if(datetime){
												datetime.setHours(this.hour,this.minute,this.second,0);
											}
											// @ts-ignore
											this.$refs.Tippy.hide();
											this.$emit('input',datetime);
										}
									},
								},'确定'),
							])
							:null,
					]);
				},
				default:() => h('div',{
					staticClass:this.classes,
					attrs:{
						tabindex:this.disable?-1:0,
					},
				},[
					h('input',{
						staticClass:'lms-DatePicker_content',
						attrs:{
							readonly:true,
							tabindex:-1,
						},
						domProps:{
							value:this.showValue,
							type:'text',
							placeholder:this.placeholder,
							disabled:this.disable,
						}
					}),
					h(Icon,{
						staticClass:'lms-DatePicker_icon',
						props:{
							name:'calendar_today'
						}
					}),
					h(Icon,{
						staticClass:'lms-DatePicker_clear',
						props:{
							name:'cancel'
						},
						on:{
							click:(e:Event) => {
								e.stopPropagation();
								this.$emit('input',null);
							}
						}
					})
				]),
			}
		});
	}
});
